﻿// Copyright 2009 William P. Hickey Jr. and William U. Walker
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//     
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.ComponentModel;
using AgwpePort;
using AgwpePort.Aprs;

namespace CSReporter
{
    public class AprsPacketData : INotifyPropertyChanged
    {
        Dictionary<string, int> symbolIndex = new Dictionary<string, int>();
        private AprsData aprsData;
        private AgwpeMoniUnproto ax25Packet;

        public int Altitude
        {
            get { return aprsData.Altitude; }
        }

        public int AntennaGain
        {
            get { return aprsData.AntennaGain; }
        }

        public string Comment
        {
            get { return aprsData.Comment; }
        }

        public int Course
        {
            get { return aprsData.Course; }
        }

        public AprsDataType DataType
        {
            get { return aprsData.DataType; }
        }

        public int HeightAboveAvgTerrain
        {
            get { return aprsData.HeightAboveAvgTerrain; }
        }

        public double Latitude
        {
            get { return aprsData.Latitude; }
        }

        public double Longitude
        {
            get { return aprsData.Longitude; }
        }

        public double RadioRange
        {
            get { return aprsData.PreCalcRadioRange > 0 ? aprsData.PreCalcRadioRange : aprsData.RadioRange; }
        }

        public int Speed
        {
            get { return aprsData.Speed; }
        }

        public int SymbolIndex
        {
            get {
                int retval;
                if(symbolIndex.TryGetValue(aprsData.SymbolTableCode.Trim(), out retval))
                    return retval;
                return 94;
            }
        }

        public string SymbolCode
        {
            get { return aprsData.SymbolTableCode; }
        }

        public int TxPower
        {
            get { return aprsData.TxPower; }
        }

        public string CallFrom
        {
            get { return ax25Packet.AX25CallFrom; }
        }

        public string CallTo
        {
            get { return ax25Packet.AX25CallTo; }
        }

        public string DigiPath
        {
            get { return ax25Packet.AX25Via; }
        }

        public DateTime Time
        {
            get {
                DateTime cur;
                DateTime.TryParse(DateTime.Now.ToShortDateString() + " " + ax25Packet.AX25Time, out cur);
                return cur;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public AprsPacketData() 
        {
            FillDictionary();
        }

        public AprsPacketData(AgwpeMoniUnproto ax25Packet)
        {
            this.aprsData = new AprsData(ax25Packet.AX25Data);
            this.ax25Packet = ax25Packet;
            FillDictionary();
        }

        public AprsData GetAprsData()
        {
            return aprsData;
        }

        public AgwpeMoniUnproto GetAX25PacketData()
        {
            return ax25Packet;
        }

        private void NotifyPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        private void FillDictionary()
        {
            // Add the elements to the dictionary.
            symbolIndex.Add("/!", 0);
            symbolIndex.Add("/\"", 1);
            symbolIndex.Add("/#", 2);
            symbolIndex.Add("S#", 2);   // "S" table
            symbolIndex.Add("D#", 2);   // "D" table
            symbolIndex.Add("/$", 3);
            symbolIndex.Add("/%", 4);
            symbolIndex.Add("/&", 5);
            symbolIndex.Add("S&", 5);   // "S" table
            symbolIndex.Add("D&", 5);   // "D" table
            symbolIndex.Add("/'", 6);
            symbolIndex.Add("/(", 7);
            symbolIndex.Add("/)", 8);
            symbolIndex.Add("/*", 9);
            symbolIndex.Add("/+", 10);
            symbolIndex.Add("/,", 11);
            symbolIndex.Add("/-", 12);
            symbolIndex.Add("/.", 13);
            symbolIndex.Add("//", 14);
            symbolIndex.Add("/0", 15);
            symbolIndex.Add("/1", 16);
            symbolIndex.Add("/2", 17);
            symbolIndex.Add("/3", 18);
            symbolIndex.Add("/4", 19);
            symbolIndex.Add("/5", 20);
            symbolIndex.Add("/6", 21);
            symbolIndex.Add("/7", 22);
            symbolIndex.Add("/8", 23);
            symbolIndex.Add("/9", 24);
            symbolIndex.Add("/:", 25);
            symbolIndex.Add("/;", 26);
            symbolIndex.Add("/<", 27);
            symbolIndex.Add("/=", 28);
            symbolIndex.Add("/>", 29);
            symbolIndex.Add("/?", 30);
            symbolIndex.Add("/@", 31);
            symbolIndex.Add("/A", 32);
            symbolIndex.Add("/B", 33);
            symbolIndex.Add("/C", 34);
            symbolIndex.Add("/D", 35);
            symbolIndex.Add("/E", 36);
            symbolIndex.Add("/F", 37);
            symbolIndex.Add("/G", 38);
            symbolIndex.Add("/H", 39);
            symbolIndex.Add("/I", 40);
            symbolIndex.Add("/J", 41);
            symbolIndex.Add("/K", 42);
            symbolIndex.Add("/L", 43);
            symbolIndex.Add("/M", 44);
            symbolIndex.Add("/N", 45);
            symbolIndex.Add("/O", 46);
            symbolIndex.Add("/P", 47);
            symbolIndex.Add("/Q", 48);
            symbolIndex.Add("/R", 49);
            symbolIndex.Add("/S", 50);
            symbolIndex.Add("/T", 51);
            symbolIndex.Add("/U", 52);
            symbolIndex.Add("/V", 53);
            symbolIndex.Add("/W", 54);
            symbolIndex.Add("/X", 55);
            symbolIndex.Add("/Y", 56);
            symbolIndex.Add("/Z", 57);
            symbolIndex.Add("/[", 58);
            symbolIndex.Add("/\\", 59);
            symbolIndex.Add("/]", 60);
            symbolIndex.Add("/^", 61);
            symbolIndex.Add("/_", 62);
            symbolIndex.Add("/`", 63);
            symbolIndex.Add("/a", 64);
            symbolIndex.Add("/b", 65);
            symbolIndex.Add("/c", 66);
            symbolIndex.Add("/d", 67);
            symbolIndex.Add("/e", 68);
            symbolIndex.Add("/f", 69);
            symbolIndex.Add("/g", 70);
            symbolIndex.Add("/h", 71);
            symbolIndex.Add("/i", 72);
            symbolIndex.Add("/j", 73);
            symbolIndex.Add("/k", 74);
            symbolIndex.Add("/l", 75);
            symbolIndex.Add("/m", 76);
            symbolIndex.Add("/n", 77);
            symbolIndex.Add("/o", 78);
            symbolIndex.Add("/p", 79);
            symbolIndex.Add("/q", 80);
            symbolIndex.Add("/r", 81);
            symbolIndex.Add("/s", 82);
            symbolIndex.Add("/t", 83);
            symbolIndex.Add("/u", 84);
            symbolIndex.Add("/v", 85);
            symbolIndex.Add("/w", 86);
            symbolIndex.Add("/x", 87);
            symbolIndex.Add("/y", 88);
            symbolIndex.Add("/z", 89);
            symbolIndex.Add("/{", 90);
            symbolIndex.Add("/|", 91);
            symbolIndex.Add("/}", 92);
            symbolIndex.Add("/~", 93);
        }
    }

    /// <summary>
    /// Storage class for a List of AprsPacketData objects.
    /// This class uses a singleton design pattern.
    /// </summary>
    public class AprsPacketList : BindingList<AprsPacketData>
    {
        // Static initialization ensures thread safety.
        private static readonly AprsPacketList singletonInstance = new AprsPacketList();

        private AprsPacketList() { }

        public static AprsPacketList GetAprsPacketList()
        {
            return singletonInstance;
        }

        public bool AddPositionPacket(AgwpeMoniUnproto ax25Packet)
        {
            if (Items.Count > 0)
            {
                for (int index = 0; index < Items.Count; index++)
                {
                    if (Items[index].CallFrom == ax25Packet.AX25CallFrom)
                    {
                        Items[index] = new AprsPacketData(ax25Packet);
                        return true;
                    }
                }
            }
            Add(new AprsPacketData(ax25Packet));
            return true;
        }
    }
}
